<template>
    <scroll :data="data" class="listview" ref="listView"
            :probeType="probeType"
            :listenScroll="listenScroll"
            @scroll="scroll"
    >
        <!-- 列表 -->
        <ul class="listview-content">
            <!-- 列表标题 -->
            <li v-for="(group, index) in data" class="list-group" ref="listGroup" :key="index">
                <h1 class="list-group-title">{{group.title}}</h1>
                <!-- 标题下的元素 -->
                <ul>
                    <li class="list-group-item" @click="selectItem(item)"
                        v-for="(item, index) in group.items" :key="index"
                    >
                        <img class="avatar" v-lazy="item.avatar">
                        <span class="name">{{item.name}}</span>
                    </li>
                </ul>
            </li>
        </ul>
        <!-- 右侧导航 -->
        <transition name="fade">
            <div class="list-shortcut" v-show="shortcutVisible"
                 @touchstart="onShortcutTouchStart"
                 @touchmove.stop.prevent="onShortcutTouchMove"
                 @touchend="onShortcutTouchEnd"
                 ref="shortcutWrapper"
            >
                <ul>
                    <li v-for="(item, index) in shortcutList" class="item"
                        :key="index" :data-index="index"
                        :class="{'current': currentIndex===index}"
                        ref="shortcutList"
                    >
                        {{item}}
                    </li>
                </ul>
                <transition name="bubble-fade">
                    <div class="bubble" v-show="shortcutClicked" ref="bubble">
                        <p class="text">{{bubbleText}}</p>
                    </div>
                </transition>
            </div>
        </transition>
        <div class="list-fixed" v-show="fixedTitle" ref="fixedTitle">
            <h1 class="fixed-title">{{fixedTitle}}</h1>
        </div>
        <div class="loading-container" v-show="!data.length">
            <loading></loading>
        </div>
    </scroll>
</template>

<script type="text/ecmascript-6">
    import Scroll from 'base/scroll/scroll'
    import Loading from 'base/load/load'
    import { getData, getStyle } from 'common/js/dom'
    import { REFRESH_TIME } from 'common/js/config'

    const LIVE_TIME = 2000

    const SELECT_EVENT = 'select'

    // 每个shortcut元素的高度
    const ANCHOR_HIGHT = 18
    // title高度
    const TITLE_HIGHT = 30
    // 气泡偏移量
    const BUBBLE_OFFSET_Y = -6

    export default {
        name: 'list-view',
        data() {
            return {
                shortcutVisible: false,
                scrollY: -1,
                currentIndex: 0,
                shortcutClicked: false,
                diff: -1
            }
        },
        props: {
            data: {
                type: Array,
                default: () => {
                    return []
                }
            }
        },
        created() {
            // touch不需要监听变化，不用添加到data中
            this.touch = {}
            this.listenScroll = true
            this.listHeight = []
            this.probeType = 3
        },
        computed: {
            shortcutList() {
                return this.data.map((group) => {
                    return group.title.substr(0, 1)
                })
            },
            bubbleText() {
                return this.shortcutList[this.currentIndex]
            },
            fixedTitle() {
                if (this.scrollY > 0) {
                    return ''
                }
                return this.data[this.currentIndex] ? this.data[this.currentIndex].title : ''
            }
        },
        methods: {
            selectItem(item) {
                this.$emit(SELECT_EVENT, item)
            },
            // 列表滑动，导航栏对应区块高亮
            scroll(pos) {
                // 显示导航栏
                this.showShortcut()
                this.scrollY = pos.y
            },
            // 显示导航列表，并设置列表在显示的一段时间后 自动隐藏
            showShortcut() {
                this.shortcutVisible = true
                // 更新计时器
                clearTimeout(this.timer)
                this.timer = setTimeout(() => {
                    this.shortcutVisible = false
                }, LIVE_TIME)
            },
            // 点击导航栏 置顶对应标签
            onShortcutTouchStart(el) {
                // 拦截点击到元素
                if (el.target === this.$refs.shortcutWrapper) {
                    return
                }
                // 滚动list-view列表
                let anchorIndex = getData(el.target, 'index')
                this._scrollTo(anchorIndex)

                // 记录触摸位置
                this.touch.firstTouch = el.touches[0].pageY
                this.touch.anchorIndex = anchorIndex

                this.showBubble(this.touch.firstTouch)
            },
            // 滑动到的标签置顶
            onShortcutTouchMove(el) {
                // 拦截点击到元素
                if (el.target === this.$refs.shortcutWrapper) {
                    return
                }
                // 记录移动位置
                this.touch.moveTouch = el.touches[0].pageY
                // 计算滑过的元素  利用（| 0）向下取整
                let dalta = (this.touch.moveTouch - this.touch.firstTouch) / ANCHOR_HIGHT | 0
                let anchorIndex = parseInt(this.touch.anchorIndex) + dalta
                // 滚动list-view列表
                this._scrollTo(anchorIndex)

                this.showBubble(this.touch.moveTouch)
            },
            onShortcutTouchEnd() {
                this.shortcutClicked = false
            },
            // 设置并显示导航栏气泡
            showBubble(y) {
                let list = this.$refs.shortcutList
                // 导航列表第一个元素顶部相对于视口的位置
                let firstDomTopY = list[0].getBoundingClientRect().top
                // 导航列表最后一个元素底部相对于视口的位置
                let lastDomBottomY = list[list.length - 1].getBoundingClientRect().top + ANCHOR_HIGHT

                // 导航列表宽度
                let len = lastDomBottomY - firstDomTopY
                // 滑动值,稍高于触摸位置
                let dalta = y - firstDomTopY + BUBBLE_OFFSET_Y

                // 处理边界
                if (dalta < 0) {
                    dalta = 0
                } else if (dalta > len) {
                    dalta = len
                }
                // 设置气泡位置
                let top = dalta + 'px'
                getStyle(this.$refs.bubble, 'top', top)
                // 显示气泡
                this.shortcutClicked = true
            },
            // 滑动到指定元素
            _scrollTo(index) {
                // 边界处理
                if (index < 0) {
                    index = 0
                } else if (index > this.listHeight.length - 2) {
                    index = this.listHeight.length - 2
                }

                // 显示导航栏
                this.showShortcut()

                // 滚动列表 并修改scrolly使得导航栏可以相应 列表的滚动
                this.scrollY = -(this.listHeight[index])
                this.$refs.listView.scrollToElement(this.$refs.listGroup[index], 0)
            },
            // 获取列表每一类所在的clientHeight
            _calculateHeight() {
                // 数据初始化
                this.listHeight = []
                const list = this.$refs.listGroup

                // 填充数组
                let height = 0
                this.listHeight.push(height)
                for (let i = 0, len = list.length; i < len; i++) {
                    let item = list[i]
                    height += item.clientHeight
                    this.listHeight.push(height)
                }
            },
            refresh() {
                this.$refs.listView.refresh()
            }
        },
        watch: {
            data() {
                // 在列表数据变化时，即计算并生成每类型列表的高度
                // 计时函数使得函数的调用 在dom渲染完成之后
                setTimeout(() => {
                    this._calculateHeight()
                }, REFRESH_TIME)
            },
            scrollY(newY) {
                const listHeight = this.listHeight

                // 在第一个标题向上滑
                if (newY > 0) {
                    this.currentIndex = 0
                    return
                }
                // 在中间部分滚动
                for (let i = 0, len = listHeight.length - 1; i < len; i++) {
                    let heightTop = listHeight[i]
                    let heightBottom = listHeight[i + 1]
                    if (-newY >= heightTop && -newY < heightBottom) {
                        // 导航栏索引
                        this.currentIndex = i

                        // 计算当前滑动的值 到当前类底部的距离 供fixedTitle使用
                        this.diff = heightBottom + newY
                        return
                    }
                }
                // 当在最底部向下滑时
                this.currentIndex = listHeight.length - 2
            },
            // 根据当前滑动位置到当前类底部的距离 得出fixedTitle的偏移量
            diff(newVal) {
                let fixedTop = (newVal > 0 && newVal < TITLE_HIGHT) ? (newVal - TITLE_HIGHT) : 0
                if (this.fixedTop === fixedTop) {
                    return
                }
                this.fixedTop = fixedTop

                getStyle(this.$refs.fixedTitle, 'transform', `translate3d(0,${fixedTop}px,0)`, true)
            }
        },
        components: {
            Scroll,
            Loading
        }
    }
</script>

<style scoped lang="stylus" rel="stylesheet/stylus">
    @import "~common/stylus/variable"

    .listview
        position: relative
        width: 100%
        height: 100%
        overflow: hidden
        background: $color-background
        .listview-content
            padding-bottom: 100px
            .list-group
                padding-bottom: 30px
                .list-group-title
                    height: 30px
                    line-height: 30px
                    padding-left: 20px
                    font-size: $font-size-small
                    color: $color-text-l
                    background: $color-highlight-background
                .list-group-item
                    display: flex
                    align-items: center
                    padding: 20px 0 0 30px
                    .avatar
                        width: 50px
                        height: 50px
                        border-radius: 50%
                    .name
                        margin-left: 20px
                        color: $color-text
                        font-size: $font-size-medium
        /* 导航渐隐动画 */
        .fade-leave-active
            transition: opacity 2s
        .fade-leave-to
            opacity: 0
        .list-shortcut
            position: absolute
            z-index: 30
            right: 7px
            top: 45%
            transform: translateY(-50%)
            text-align: center
            width: 20px
            padding: 10px 0
            border-radius: 10px
            background: $color-background-w
            font-family: Helvetica
            .item
                padding: 3px
                color: $color-text-d
                font-size: $font-size-small
                &.current
                    color: $color-theme
                    font-weight: bolder
            /* 导航气泡渐隐动画 */
            .bubble-fade-enter-active, .bubble-fade-leave-active
                transition: opacity .3s
            .bubble-fade-enter, .bubble-fade-leave-to
                opacity: 0
            .bubble
                position: absolute
                left: -60px
                top: 6px
                width: 40px
                height: 40px
                transform: rotate(-45deg)
                border-radius: 50%
                border-bottom-right-radius: 0
                background: $color-background-w
                z-index: 30
                .text
                    height: 40px
                    line-height: 40px
                    transform: rotate(45deg)
                    font-size: $font-size-large
                    color: $color-theme
        /*
            使用伪类遮住fixedTitle上面一部分
            防止下方列表滑动时，在fixedTitle透出
        */
        .list-fixed::before
            content: ''
            position: absolute
            top: -2px
            left: 0
            width: 100%
            height: 3px
            background: $color-highlight-background
        .list-fixed
            position: absolute
            top: 0
            left: 0
            width: 100%
            .fixed-title
                height: 30px
                line-height: 30px
                padding-left: 20px
                font-size: $font-size-small
                color: $color-text-l
                background: $color-highlight-background
        .loading-container
            position: absolute
            width: 100%
            top: 50%
            transform: translateY(-50%)
</style>
